﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;

namespace Qzb.DBHelper.Utilities
{
    /// <summary>
    /// 对象映射信息
    /// </summary>
    [Serializable]
    public class ObjectMappingInfo
    {
        private static ConcurrentDictionary<string, ObjectMappingInfo> sCaches = new ConcurrentDictionary<string, ObjectMappingInfo>();

        private const string mObjectMapCacheKey = "ObjectMap_";
        private const string mDefaultPrimaryKey = "ItemID";

        public string CacheByProperty { get; set; }

        public string CacheKey
        {
            get
            {
                string _CacheKey = "ObjectCache_" + TableName + "_";
                if (!string.IsNullOrEmpty(CacheByProperty))
                {
                    _CacheKey = _CacheKey + CacheByProperty + "_";
                }
                return _CacheKey;
            }
        }

        public int CacheTimeOutMultiplier { get; set; }

        public Dictionary<string, string> ColumnNames { get; } = new Dictionary<string, string>();

        public string ObjectType { get; set; }

        public string PrimaryKey { get; set; }

        public Dictionary<string, PropertyInfo> Properties { get; } = new Dictionary<string, PropertyInfo>();

        public string TableName { get; set; }

        /// <summary>
        /// 获取对象映射信息
        /// </summary>
        /// <param name="objType">对象类型</param>
        /// <returns></returns>
        public static ObjectMappingInfo GetObjectMapping(Type objType)
        {
            var cacheKey = mObjectMapCacheKey + objType.FullName;
            try
            {
                if (sCaches.TryGetValue(cacheKey, out ObjectMappingInfo objMap) && objMap != null)
                    return objMap;

                objMap = new ObjectMappingInfo
                {
                    ObjectType = objType.FullName,
                    PrimaryKey = GetPrimaryKey(objType),
                    TableName = GetTableName(objType)
                };

                foreach (PropertyInfo objProperty in objType.GetProperties())
                {
                    objMap.Properties.Add(
                        objProperty.Name.ToUpperInvariant(),
                        objProperty);

                    objMap.ColumnNames.Add(
                        objProperty.Name.ToUpperInvariant(),
                        GetColumnName(objProperty));
                }
                sCaches.AddOrUpdate(cacheKey, objMap, (k, m) =>
                {
                    return m;
                });

                return objMap;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 初始化对象各属性
        /// </summary>
        /// <param name="objObject">需初始化的对象</param>
        /// <returns>初始化后的对象</returns>
        public static object InitializationObject(object objObject)
        {
            return InitializationObject(objObject, objObject.GetType());
        }

        /// <summary>
        /// 初始化对象各属性
        /// </summary>
        /// <param name="objObject">需初始化的对象</param>
        /// <param name="objType">需初始化的对象的类型</param>
        /// <returns>初始化后的对象</returns>
        public static object InitializationObject(object objObject, Type objType)
        {
            var objMapping = GetObjectMapping(objType);
            if (objMapping == null)
                return null;

            try
            {
                foreach (var objPropertyInfo in objMapping.Properties.Values)
                {
                    if (objPropertyInfo.CanWrite)
                    {
                        objPropertyInfo.SetValue(objObject, Null.GetNull(objPropertyInfo), null);
                    }
                }
                return objObject;
            }
            catch
            {
                return null;
            }
        }

        private static string GetPrimaryKey(Type objType)
        {
            return mDefaultPrimaryKey;
        }

        private static string GetTableName(Type objType)
        {
            return objType.Name;
        }

        private static string GetColumnName(PropertyInfo objProperty)
        {
            return objProperty.Name;
        }
    }
}
